package com.corpgovernment.common.requestprocess;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import com.ctrip.corp.obt.generic.utils.EnvironmentHolder;

/**
 * 异步任务执行工具类
 * 
 * @author dlz
 * @since 2022/1/5
 */
public final class TaskHelper {

    private TaskHelper() {}

    /**
     * 正在执行中的任务队列
     */
    private final List<Future<?>> runningTaskList = new ArrayList<>();

    /**
     * 用于执行任务的线程池名，对应QConfig中的ExecutorSetting配置
     */
    private ThreadPoolExecutor executor;

    /**
     * 超时时间
     */
    private Integer timeout;

    /**
     * 使用传入的线程池名的TaskHelper
     */
    public static TaskHelper newHelper(String threadPoolName) {
        TaskHelper taskHelper = new TaskHelper();
        taskHelper.executor = (ThreadPoolExecutor)EnvironmentHolder.getBean(threadPoolName);
        return taskHelper;
    }

    /**
     * 执行一个任务并消费其结果
     * 
     * @param task 需要执行的任务
     * @param consumer 任务返回值的消费者
     * @return this
     */
    public <T> TaskHelper exec(Supplier<T> task, Consumer<T> consumer) {
        Future<?> future = executor.submit(LogContextUtil.wrap(() -> {
            // 执行任务并获取结果
            T result = task.get();
            // 对任务的结果进行消费
            if (consumer != null) {
                consumer.accept(result);
            }
        }));

        runningTaskList.add(future);
        return this;
    }

    /**
     * 执行一堆入参为R类型的任务并消费其结果
     * 
     * @param itemList 提供参数的列表
     * @param task 需要执行的任务(入参为itemList的item)
     * @param consumer 任务返回值的消费者(入参为task的结果)
     * @return this
     */
    public <R, T> TaskHelper execBatch(Collection<R> itemList, Function<R, T> task, Consumer<T> consumer) {
        for (R item : itemList) {
            Future<?> future = executor.submit(LogContextUtil.wrap(() -> {
                // 执行任务并获取结果
                T result = task.apply(item);
                // 对任务的结果进行消费
                if (consumer != null) {
                    consumer.accept(result);
                }
            }));

            runningTaskList.add(future);
        }
        return this;
    }

    /**
     * 启动一个任务
     * 
     * @param task 需要执行的任务
     * @return this
     */
    public TaskHelper exec(Runnable task) {
        return exec(() -> {
            task.run();
            return null;
        }, null);
    }

    /**
     * 启动一堆入参为R类型的任务
     *
     * @param itemList 提供参数的列表
     * @param task 需要执行的任务(入参为itemList的item)
     * @return this
     */
    public <R> TaskHelper execBatch(Collection<R> itemList, Consumer<R> task) {
        return execBatch(itemList, item -> {
            task.accept(item);
            return null;
        }, null);
    }

    /**
     * 设置超时时间,单位s
     */
    public TaskHelper setTimeout(int timeout) {
        this.timeout = timeout;
        return this;
    }

    /**
     * 等等所有的任务执行完成
     */
    public void waitAllThrow() {
        if (timeout == null) {
            AsyncTaskUtil.waitAllThrow(runningTaskList, 10, TimeUnit.SECONDS);
        } else {
            AsyncTaskUtil.waitAllThrow(runningTaskList, timeout, TimeUnit.SECONDS);
        }
    }
}
